// thread-specific_storage.cpp


#include <csignal>
#include <cstdio>
#include <cstdlib>

#include <chrono>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>


namespace blogs
{


using std::chrono::milliseconds;
using std::endl;
using std::ofstream;
using std::ostringstream;
using std::string;


string this_thread_id()
{
    ostringstream oss;
    oss << std::this_thread::get_id();
    return oss.str();
}


class Logger
{

  private:

    static
    thread_local
    ofstream
    __ofs__;


  public:

    void println(string message)
    {
        __ofs__ << "(" << &__ofs__ << ")" << message << endl;
    }


    void close()
    {
        __ofs__.close();
    }

};


class Client
{

  private:

    string
    __name__;


    Logger
    __logger__;


  public:

    Client(string nm)
        : __name__(nm)
    {}


    void run()
    {
        string id = this_thread_id();
        std::printf("%s(%s) BEGIN\n", __name__.c_str(), id.c_str());
        for (int i = 0; i < 10; ++i) {
            string msg;
            msg += "i = ";
            msg += std::to_string(i);
            __logger__.println(msg);
            std::this_thread::sleep_for(milliseconds(100));
        }
        __logger__.close();
        std::printf("%s(%s) END\n", __name__.c_str(), id.c_str());
    }

};


thread_local ofstream Logger::__ofs__(this_thread_id() + ".log");


void
bye(int sig = SIGTERM)
{
    std::printf("\nBye Thread-Specific Storage...\n\n");
    std::exit(sig);
}


} // end of namespace blogs


int
main(int argc, char * argv[])
{
    using std::thread;
    using blogs::Client;

    std::signal(SIGINT, blogs::bye);

    Client alice("Alice");
    Client bobby("Bobby");
    Client chris("Chris");

    thread t1(&Client::run, &alice);
    thread t2(&Client::run, &bobby);
    thread t3(&Client::run, &chris);
    t1.join();
    t2.join();
    t3.join();

    blogs::bye();
    return 0;
}

